#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>


int is_start = 0;
int is_end = 0;
int copy_result = 0;


void signal_handler(int signum);
void copy_file(const char* src_file, const char* dst_file);
void ui(pid_t child);


int main(int argc, char** argv)
{
    if(argc != 3)
    {
        fprintf(stderr, "命令用法错误！\n");
        return 1;
    }

    if(-1 == access(argv[1], R_OK))
    {
        fprintf(stderr, "待拷贝的文件不存在或不可读！\n");
        return 1;
    }

    if(0 == access(argv[2], F_OK))
    {
        printf("目标文件 %s 已存在，是否覆盖？(Y/n)", argv[2]);

        char choice = getchar();
        if(choice == 'Y' || choice == 'y')
        {
            while(getchar() != '\n');
        }
        else
            return 1;
    }    

    pid_t pid = fork();

    if(pid == -1) 
    {
        perror("fork");
        return 1;
    }

    if(pid == 0)
    {
        // 子进程负责拷贝文件任务
        signal(SIGTERM, signal_handler);
        signal(SIGRTMIN + 1, signal_handler);
        signal(SIGRTMIN + 2, signal_handler);

        copy_file(argv[1], argv[2]);
    }
    else
    {
        // 父进程负责 UI 处理任务
        signal(SIGCHLD, signal_handler);
        signal(SIGRTMIN + 3, signal_handler);

        ui(pid);
    }
    
    return 0;
}


void signal_handler(int signum)
{
    if(signum == SIGTERM)
    {
        is_end = 1;
    }
    else if(signum == SIGCHLD)
    {
        is_end = 1;
    }
    else if(signum == SIGRTMIN + 1)
    {
        is_start = 1;
    }
    else if(signum == SIGRTMIN + 2)
    {
        is_start = 0;
    }
    else if(signum == SIGRTMIN + 3)
    {
        copy_result = 1;
    }
}


void copy_file(const char* src_file, const char* dst_file)
{
    int fd_src, fd_dst;
    unsigned int ret, write_cnt = 0;
    char buf[1024];
    struct stat st;

    fd_src = open(src_file, O_RDONLY);
    fd_dst = open(dst_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);

    fstat(fd_src, &st);

    while((ret = read(fd_src, buf, sizeof(buf))) > 0)
    {
        while(!is_end && !is_start) pause();

        if(is_end) 
        {   
            unlink(dst_file);
            break;
        }

        ret = write(fd_dst, buf, ret);

        if(ret == -1) break;

        write_cnt += ret;
    }

    close(fd_src);
    close(fd_dst);

    if(!is_end)
    {
        if(write_cnt == st.st_size)
            kill(getppid(), SIGRTMIN + 3);
    }
}


void ui(pid_t child)
{
    int op;

    printf("欢迎使用本拷贝工具！\n\n");
    printf("使用帮助：\n");
    printf("开始或继续拷贝请输入 1\n");
    printf("暂停拷贝请输入 2\n");
    printf("查看拷贝状态请输入 3\n");    
    printf("退出程序请输入 0\n");

    while(1)
    {
        printf("\n:> ");

        if(1 != scanf("%d", &op))
        {
            op = -1;
            while(getchar() != '\n');
        }

        switch(op)
        {
            case 0:
            {
                kill(child, SIGTERM);
                printf("\n感谢您的使用，下次再见！\n");
                exit(0);
            }
            break;

            case 1:
            {
                kill(child, SIGRTMIN + 1);
                is_start = 1;
            }
            break;

            case 2:
            {
                kill(child, SIGRTMIN + 2);
                is_start = 0;
            }
            break;

            case 3:
            {
                if(is_end)
                {
                    if(copy_result)
                        printf("拷贝已经成功完成！\n");
                    else
                        printf("拷贝失败！\n");
                }
                else
                {
                    if(is_start)
                        printf("拷贝正在进行，可以输入 2 暂停拷贝！\n");
                    else
                        printf("拷贝已经暂停，可以输入 1 继续拷贝！\n");                    
                }
            }
            break;

            default:
            {
                printf("\n输入错误，请重新输入！\n");
            }
        }
    }
}

